﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Practices.Unity;
using PicStore.BLL.Interface;
using PicStore.DAL;
using PicStore.Model;

namespace PicStore.BLL.Impl
{
    public class PictureService : BaseService, IPictureService 
    {
        [Dependency]
        public IUserService UserService { get; set; }

        private PictureInfo BuildPictureInfo(Picture pic)
        {
            if (pic == null)
            {
                return null;
            }

            var picture = new PictureInfo()
            {
                Id = pic.PictureId,
                PicturePhysicalFullName = pic.PicturePhysicalFullName,
                PictureOnlyFileName = pic.PictureOnlyFileName,
                RelativePictureName = pic.PictureRelativeName,
                Place = pic.Place,
                Sex = pic.Sex,
                Item = pic.Item,
                Color = pic.Color,
                Style = pic.Style,
                Length = pic.Length,
                Collar = pic.Collar,
                Front = pic.Front,
                Sleeve = pic.Sleeve,
                SweaterTexture = pic.SweaterTexture,
                Type = pic.Type,
                CreateTime = pic.UploadDate,
                TakePhotoDate = pic.TakePhotoDate,
                LastUpdateTime = pic.LastUpdateTime,
                CreaterId = pic.UploaderId,
                CreaterName = UserService.GetUser(pic.UploaderId).UserName,
                OperatorId = pic.OperatorId,
                OperatorName = UserService.GetUser(pic.OperatorId).UserName,
            };

            return picture;
        }

        public List<PictureInfo> GetPictureList(int userId, DateTime fromDate, DateTime toDate, string orderby, out int count, out int totalPages, int pageSize, int pageIndex = 1, bool isAsc = true)
        {
            var currentUser = UserService.GetUser(userId);
            List<PictureInfo> list = new List<PictureInfo>();
            if (currentUser == null)
            {
                count = 0;
                totalPages = 0;
                return list;
            }

            fromDate = fromDate.Date;
            toDate = toDate.Date.AddHours(23);
            var pictures = (from p in dbContext.Picture
                            where p.TakePhotoDate >= fromDate && p.TakePhotoDate <= toDate && p.Status == (int)PictureStatus.正常
                            select p);

            if (currentUser.Role.Name.ToLower() == RoleEnum.Contributer.ToString().ToLower())
            {
                pictures = pictures.Where(p => p.UploaderId == userId);
            }
            pictures = SetOrderPictures(@orderby, isAsc, pictures);

            count = pictures.Count();
            totalPages = count / pageSize + (count % pageSize > 0 ? 1 : 0);
            var resultList = pictures.Skip((pageIndex - 1)*pageSize).Take(pageSize).ToList();

            
            foreach (var picture in resultList)
            {
                list.Add(BuildPictureInfo(picture));
            }

            return list;
        }

        public List<PictureInfo> GetPictureList(int userId, DateTime fromDate, DateTime toDate, List<string> places, List<string> sexs,
            List<string> items, List<string> colors, List<string> styles, List<string> lengths, List<string> collars, List<string> fronts, List<string> sleeves, List<string> sweaterTextures,
            List<string> types, string orderby, out int count, out int totalPages, int pageSize, int pageIndex = 1, bool isAsc = true)
        {
            var currentUser = UserService.GetUser(userId);
            List<PictureInfo> list = new List<PictureInfo>();
            if (currentUser == null)
            {
                count = 0;
                totalPages = 0;
                return list;
            }

            fromDate = fromDate.Date;
            toDate = toDate.Date.AddHours(23);

            var pictures = (from p in dbContext.Picture
                            where p.TakePhotoDate >= fromDate && p.TakePhotoDate <= toDate && p.Status == (int)PictureStatus.正常
                            select p);
            
            if (currentUser.Role.Name.ToLower() == RoleEnum.Contributer.ToString().ToLower())
            {
                pictures = pictures.Where(p => p.UploaderId == userId);
            }

            pictures = SetFiltersOnQuery(places, sexs, items, colors, styles, lengths, collars, fronts, sleeves, sweaterTextures, types, pictures);
            pictures = SetOrderPictures(@orderby, isAsc, pictures);

            count = pictures.Count();
            totalPages = count / pageSize + (count % pageSize > 0 ? 1 : 0);

            var pictureList = pictures.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
            foreach (var picture in pictureList)
            {
                list.Add(BuildPictureInfo(picture));
            }

            return list;
        }

        #region filter and order 
        private static IQueryable<Picture> SetFiltersOnQuery(List<string> places, List<string> sexs, List<string> items, List<string> colors, List<string> styles, List<string> lengths,
                                                    List<string> collars, List<string> fronts, List<string> sleeves, List<string> sweaterTextures, List<string> types,
                                                    IQueryable<Picture> pictures)
        {
            if (places != null)
            {
                pictures = pictures.Where(p => places.Contains(p.Place));
            }
            if (sexs != null)
            {
                pictures = pictures.Where(p => sexs.Contains(p.Sex));
            }
            if (items != null)
            {
                pictures = pictures.Where(p => items.Contains(p.Item));
            }
            if (colors != null)
            {
                pictures = pictures.Where(p => colors.Contains(p.Color));
            }
            if (styles != null)
            {
                pictures = pictures.Where(p => styles.Contains(p.Style));
            }
            if (lengths != null)
            {
                pictures = pictures.Where(p => lengths.Contains(p.Length));
            }
            if (collars != null)
            {
                pictures = pictures.Where(p => collars.Contains(p.Collar));
            }
            if (fronts != null)
            {
                pictures = pictures.Where(p => fronts.Contains(p.Front));
            }
            if (sleeves != null)
            {
                pictures = pictures.Where(p => sleeves.Contains(p.Sleeve));
            }
            if (sweaterTextures != null)
            {
                pictures = pictures.Where(p => sweaterTextures.Contains(p.SweaterTexture));
            }
            if (types != null)
            {
                pictures = pictures.Where(p => types.Contains(p.Type));
            }
            return pictures;
        }

        private IQueryable<Picture> SetOrderPictures(string @orderby, bool isAsc, IQueryable<Picture> pictures)
        {
            if (@orderby == "Date")
            {
                if (isAsc)
                {
                    pictures = pictures.OrderBy(p => p.TakePhotoDate);
                }
                else
                {
                    pictures = pictures.OrderByDescending(p => p.TakePhotoDate);
                }
            }
            else if (@orderby == BaseCategoryEnum.Collar.ToString())
            {
                if (isAsc)
                {
                    pictures = pictures.OrderBy(p => p.Collar);
                }
                else
                {
                    pictures = pictures.OrderByDescending(p => p.Collar);
                }
            }
            else if (@orderby == BaseCategoryEnum.Color.ToString())
            {
                if (isAsc)
                {
                    pictures = pictures.OrderBy(p => p.Color);
                }
                else
                {
                    pictures = pictures.OrderByDescending(p => p.Color);
                }
            }
            else if (@orderby == BaseCategoryEnum.Front.ToString())
            {
                if (isAsc)
                {
                    pictures = pictures.OrderBy(p => p.Front);
                }
                else
                {
                    pictures = pictures.OrderByDescending(p => p.Front);
                }
            }
            else if (@orderby == BaseCategoryEnum.Item.ToString())
            {
                if (isAsc)
                {
                    pictures = pictures.OrderBy(p => p.Item);
                }
                else
                {
                    pictures = pictures.OrderByDescending(p => p.Item);
                }
            }
            else if (@orderby == BaseCategoryEnum.Length.ToString())
            {
                if (isAsc)
                {
                    pictures = pictures.OrderBy(p => p.Length);
                }
                else
                {
                    pictures = pictures.OrderByDescending(p => p.Length);
                }
            }
            else if (@orderby == BaseCategoryEnum.Place.ToString())
            {
                if (isAsc)
                {
                    pictures = pictures.OrderBy(p => p.Place);
                }
                else
                {
                    pictures = pictures.OrderByDescending(p => p.Place);
                }
            }
            else if (@orderby == BaseCategoryEnum.Sex.ToString())
            {
                if (isAsc)
                {
                    pictures = pictures.OrderBy(p => p.Sex);
                }
                else
                {
                    pictures = pictures.OrderByDescending(p => p.Sex);
                }
            }
            else if (@orderby == BaseCategoryEnum.Sleeve.ToString())
            {
                if (isAsc)
                {
                    pictures = pictures.OrderBy(p => p.Sleeve);
                }
                else
                {
                    pictures = pictures.OrderByDescending(p => p.Sleeve);
                }
            }
            else if (@orderby == BaseCategoryEnum.Style.ToString())
            {
                if (isAsc)
                {
                    pictures = pictures.OrderBy(p => p.Style);
                }
                else
                {
                    pictures = pictures.OrderByDescending(p => p.Style);
                }
            }
            else if (@orderby == BaseCategoryEnum.SweaterTexture.ToString())
            {
                if (isAsc)
                {
                    pictures = pictures.OrderBy(p => p.SweaterTexture);
                }
                else
                {
                    pictures = pictures.OrderByDescending(p => p.SweaterTexture);
                }
            }
            return pictures;
        }
        #endregion

        private Picture GetDALPictureById(int pictureId)
        {
            return (from p in dbContext.Picture
                    where p.PictureId == pictureId && p.Status == (int) PictureStatus.正常
                    select p).FirstOrDefault();
        }
        public PictureInfo GetPictureById(int pictureId)
        {
            var picture = GetDALPictureById(pictureId);
            if (picture == null)
            {
                return null;
            }

            return BuildPictureInfo(picture);
        }

        public void UpdatePicture(int userId, int pictureId, string place, string sex, string item, string color, string style, string length,
                           string collar, string front, string sleeve, string sweaterTexture, string type)
        {
            var pic = GetDALPictureById(pictureId);
            if (pic == null) return;

            var user = UserService.GetUser(userId);
            if (user == null)
            {
                throw new Exception(string.Format("Cannot find current user for updating picture. user id is {0}.", user.UserId));
            }
            if (user.Role.Name.ToLower() == RoleEnum.Viewer.ToString().ToLower())
            {
                throw new Exception(string.Format("current user {0}, user id is {1}. Don't have permission to update the picture.", user.UserName, user.UserId));
            }
            if (user.Role.Name.ToLower() == RoleEnum.Contributer.ToString().ToLower())
            {
                if (user.UserId != pic.UploaderId)
                {
                    throw new Exception(string.Format("current user {0}, user id is {1}. Don't have permission to update pictures which is not uploaded by him.", user.UserName, user.UserId));
                }
            }

            pic.Place = place;
            pic.Sex = sex;
            pic.Item = item;
            pic.Color = color;
            pic.Style = style;
            pic.Length = length;
            pic.Collar = collar;
            pic.Front = front;
            pic.Sleeve = sleeve;
            pic.SweaterTexture = sweaterTexture;
            pic.Type = type;
            pic.LastUpdateTime = DateTime.Now;
            pic.OperatorId = userId;

            dbContext.SubmitChanges();
        }

        public void CreatePicture(int userId, string pictureFullName, string pictureOnlyFileName, string relativeFileName, DateTime takePhotoDate, string place, string sex, string item, string color, string style, string length,
                           string collar, string front, string sleeve, string sweaterTexture, string type)
        {
            var user = UserService.GetUser(userId);
            if (user == null)
            {
                throw new Exception(string.Format("Cannot find current user for creating picture. user id is {0}.", user.UserId));
            }
            if (user.Role.Name.ToLower() == RoleEnum.Viewer.ToString().ToLower())
            {
                throw new Exception(string.Format("current user {0}, user id is {1}. Don't have permission to create the picture.", user.UserName, user.UserId));
            }

            Picture pic = new Picture();
            pic.PicturePhysicalFullName = pictureFullName;
            pic.PictureOnlyFileName = pictureOnlyFileName;
            pic.PictureRelativeName = relativeFileName;
            pic.Place = place;
            pic.Sex = sex;
            pic.Item = item;
            pic.Color = color;
            pic.Style = style;
            pic.Length = length;
            pic.Collar = collar;
            pic.Front = front;
            pic.Sleeve = sleeve;
            pic.SweaterTexture = sweaterTexture;
            pic.Type = type;
            pic.LastUpdateTime = DateTime.Now;
            pic.OperatorId = userId;
            pic.UploaderId = userId;
            pic.TakePhotoDate = takePhotoDate;
            pic.UploadDate = DateTime.Now;

            dbContext.Picture.InsertOnSubmit(pic);
            dbContext.SubmitChanges();
        }

        public void DeletePictureById(int pictureId)
        {
            var item = GetDALPictureById(pictureId);
            if (item != null)
            {
                item.Status = (int) PictureStatus.已删除;

                dbContext.SubmitChanges();
            }
        }

        public List<PictureInfoForExcel> GetPictureListForExcel(int userId, DateTime fromDate, DateTime toDate)
        {
            return GetPictureListBasic(false, userId, fromDate, toDate, null, null, null, null, null, null, null, null,
                                       null, null, null);
        }

        public List<PictureInfoForExcel> GetPictureListForExcelWithFilters(int userId, DateTime fromDate, DateTime toDate, List<string> places, List<string> sexs,
            List<string> items, List<string> colors, List<string> styles, List<string> lengths, List<string> collars, List<string> fronts, List<string> sleeves,
            List<string> sweaterTextures, List<string> types)
        {
            return GetPictureListBasic(true, userId, fromDate, toDate, places, sexs,
                                       items, colors, styles, lengths, collars, fronts, sleeves, sweaterTextures, types);
        }

        private List<PictureInfoForExcel> GetPictureListBasic(bool hasFilters, int userId, DateTime fromDate, DateTime toDate, List<string> places, List<string> sexs,
            List<string> items, List<string> colors, List<string> styles, List<string> lengths, List<string> collars, List<string> fronts, List<string> sleeves,
            List<string> sweaterTextures, List<string> types)
        {
            List<PictureInfoForExcel> result = null;
            var currentUser = UserService.GetUser(userId);
            if (currentUser != null)
            {
                fromDate = fromDate.Date;
                toDate = toDate.Date.AddHours(23);

                IQueryable<Picture> pictures = null;
                if (currentUser.Role.Name.ToLower() == RoleEnum.Contributer.ToString().ToLower())
                {
                    pictures = (from pic in dbContext.Picture
                                where
                                    pic.TakePhotoDate >= fromDate && pic.TakePhotoDate <= toDate &&
                                    pic.Status == (int)PictureStatus.正常 && currentUser.UserId == pic.UploaderId
                                select pic);
                }
                else if (currentUser.Role.Name.ToLower() == RoleEnum.Manager.ToString().ToLower() || currentUser.Role.Name.ToLower() == RoleEnum.Admin.ToString().ToLower())
                {
                    pictures = (from pic in dbContext.Picture
                                where pic.TakePhotoDate >= fromDate && pic.TakePhotoDate <= toDate && pic.Status == (int)PictureStatus.正常
                                select pic);
                }

                if (pictures != null)
                {
                    if (hasFilters)
                    {
                        pictures = SetFiltersOnQuery(places, sexs, items, colors, styles, lengths, collars, fronts, sleeves,
                                                     sweaterTextures, types, pictures);
                    }
                    var list = (from pic in pictures
                                join user in dbContext.UserProfile on pic.UploaderId equals user.UserId
                                select new PictureInfoForExcel()
                                {
                                    PictureId = pic.PictureId,
                                    PicturePhysicalFullName = pic.PicturePhysicalFullName,
                                    RelativePictureName = pic.PictureRelativeName,
                                    PictureOnlyFileName = pic.PictureOnlyFileName,
                                    Place = pic.Place,
                                    Sex = pic.Sex,
                                    Item = pic.Item,
                                    Color = pic.Color,
                                    Style = pic.Style,
                                    Length = pic.Length,
                                    Collar = pic.Collar,
                                    Front = pic.Front,
                                    Sleeve = pic.Sleeve,
                                    SweaterTexture = pic.SweaterTexture,
                                    Type = pic.Type,
                                    TakePhotoDate = pic.TakePhotoDate,
                                    CreaterName = user.UserName,
                                });

                    result = list.ToList();
                }
            }

            return result;
        }

        public bool IsPictureUploaded(string pictureOnlyFileName, out string finalServerFileName, out string relativePathName)
        {
            finalServerFileName = string.Empty;
            relativePathName = string.Empty;
            if (string.IsNullOrEmpty(pictureOnlyFileName))
            {
                return false;
            }

            bool result = false;
            var picture = (from pic in dbContext.Picture
                            where
                                pic.PictureOnlyFileName.ToLower() == pictureOnlyFileName.ToLower()
                            select pic).FirstOrDefault();

            if (picture != null)
            {
                result = true;
                finalServerFileName = picture.PicturePhysicalFullName;
                relativePathName = picture.PictureRelativeName;
            }

            return result;
        }
    }
}
